-- EX1: mylast

myLast ( x : [] ) = x

myLast (_:xs) = myLast xs

ex1 =
    putStrLn $ show ( myLast [1..100] )
   
-- EX2: butLast (lastTwo) 

lastTwo [a,b] = [a,b]

lastTwo ( a : b : cs ) = lastTwo ( b : cs )

ex2 = 
    putStrLn $ show $ lastTwo [1..100]

-- EX3: nth

nth 1 ( x : xs ) = x
nth n ( x : xs ) = nth (n-1) xs

ex3 = 
    putStrLn $ show $ nth 44 [1..100]

-- EX4: len

len [] = 0
len (x:xs) = ( len xs ) + 1

ex4 = 
    putStrLn $ show $ len [1..166]

-- EX5: reverse
rev [] = []
rev (x:xs) = (rev xs) ++ [x]

ex5 = 
    putStrLn $ show $ rev "hello world!"

-- EX6: isPal

-- isPal l = foldl (&&) True [ a == b |  (a,b) <-  (zip l (reverse l))]
isPal l = let base = floor (  (fromIntegral (length l))  / 2 ) in 
            (take  base l ) == (take base (reverse l))

ex6 = do
    putStrLn $ show $ isPal "hello olleh"
    putStrLn $ show $ isPal ""
    putStrLn $ show $ isPal "h"
    putStrLn $ show $ isPal "nopal"

-- EX7: flatten

data List a = Elem a | List [List a]

flatten l = case l of
    Elem a -> [a]
    List a -> concat (map flatten a)
    
ex7 = do
    putStrLn $ show $ flatten (List [Elem 1, Elem 2])
    putStrLn $ show $ flatten (List [Elem 1, List [Elem 2, Elem 3]])
    
-- EX8: compress

compress (x:xs) = [x]++ icompress xs x
icompress [] _ = []
icompress (x:xs) e = if x == e 
                        then
                            icompress xs e
                        else
                            [x]++icompress xs x

ex8 = do
    putStrLn $ show $ compress "aaaaabbbbbbaabbbbccccc"

   
-- EX9: pack

partition [] l = [l,[]]
partition [x] l = [l++[x],[]]
partition (x:y:xs) l = if x == y 
                then
                    partition (y:xs) (l++[x])
                else
                    [l++[x], (y:xs)]
                    
pack [] = []
pack l = let (same:rest:[]) = partition l [] in
            [same]++(pack rest)
ex9 = do
    putStrLn $ show $ pack "aaaaabbbbbbaabbbbccccc" 

-- EX10: rle

rle l = map (\x -> (length x, head x)) (pack l)
ex10 = do
    putStrLn $ show $ rle "aaaaabbbbbbaabbbbccccc" 

-- EX11: mrle

data Rle a = Single a | Multiple Int a
    deriving Show

pick x = let ln = length x in
            if ln == 1
                then
                    Single (head x)
                else
                    Multiple ln (head x)
                    
mrle l = map pick (pack l)
ex11 = do
    putStrLn $ show $ mrle "aaaaabbbbbbsaabbbbcccccz" 

-- EX12: decode mrle

dmrle [] = []
dmrle ((Single x):xs) = [x]++(dmrle xs)
dmrle ((Multiple 1 x):xs) = [x]++(dmrle xs)
dmrle ((Multiple n x):xs) = [x]++(dmrle ((Multiple (n-1) x):xs))

ex12 = do
    putStrLn $ show $ dmrle (mrle "aaaaabbbbbbsaabbbbcccccz" )

-- EX13: dupli

dupli = concatMap (\x -> [x,x])

ex13 = do
    putStrLn $ show $ dupli "abcd"

-- EX14: repli

repli l n = concatMap (\x -> [x| z <- [1..n]]) l

ex14 = do
    putStrLn $ show $ repli "abcd" 4
    
main = do
    ex1    
    ex2
    ex3
    ex4
    ex5
    ex6
    ex7
    ex8
    ex9
    ex10
    ex11
    ex12
    ex13
    ex14